/* main.c */
#include "app_inc.h"

/*
对发送中断的使用：
1. 当发送缓冲区为空时触发发送中断
2. 当有数据需要发送时，仅仅需要开放发送中断，发送中断服务程序会自动开始搬运数据到发送缓冲区中
3. 在发送中断服务程序中判断，若当前搬运的数据为发送队列的最后一个数，则在搬运数据之后自动关闭中断
对接收中断的使用：
1. 当接收缓冲区被填充后触发接收中断
2. 接收中断时时刻刻都保持激活状态，捕获外部数据
3. 在中断服务程序中，将捕获数据填充到数据队列中，之后启用对应的发送过程
中断优先级：
1. 利用中断优先级实现硬件的多任务，中断服务程序相当于是多任务系统中的每个任务
2. 接收中断的优先级总体上高于发送中断的优先级，确保外部传入数据不会丢失
3. LPUART1的接收中断优先级高于LPUART0：
    BLE模块发出的数据总是优先需要捕获到的；
    而用户发出的数据如果出错，可以重发，故优先级相对较低
*/

/* 配置项 */
#define APP_LPUART0_BAUDRATE  115200U
#define APP_LPUART0_RX_BUF_LEN 16

#define APP_LPUART1_BAUDRATE  115200U
#define APP_LPUART1_RX_BUF_LEN 16

/* 静态内存分配 */
uint8_t gLpuart0BufData[APP_LPUART0_RX_BUF_LEN];
uint8_t gLpuart1BufData[APP_LPUART1_RX_BUF_LEN];
RBUF_Handler_T gLpuart0RxRBufStruct;
RBUF_Handler_T gLpuart1RxRBufStruct;
volatile uint32_t gLpuart0OverflowCount;
volatile uint32_t gLpuart1OverflowCount;

volatile uint32_t gLpuart0TxCounter;
volatile uint32_t gLpuart1TxCounter;

/* 函数声明 */
void NVIC_Configuration(void);
void LPUART0_Configuration(void);
void LPUART1_Configuration(void);
void GPIO_Configuration(void);

int main(void)
{
    BSP_InitSystem();

    /* 准备数据缓冲区 */
    gLpuart0TxCounter = 0U;
    gLpuart1TxCounter = 0U;
    gLpuart0OverflowCount = 0U;
    gLpuart1OverflowCount = 0U;
    RBUF_Init(&gLpuart0RxRBufStruct, gLpuart0BufData, APP_LPUART0_RX_BUF_LEN);
    RBUF_Init(&gLpuart1RxRBufStruct, gLpuart1BufData, APP_LPUART1_RX_BUF_LEN);

    /* 配置引脚 */
    BSP_InitLpuartForDebug(); /* LPUART0. */
    BSP_InitLpuartForBLE();   /* LPUART1. */
    BSP_InitGpioForBLE();     /* GPIO - BLE. */

    /* 配置功能模块 */
    NVIC_Configuration();
    LPUART0_Configuration();
    LPUART1_Configuration();
    GPIO_Configuration();

    /* Start. */
    LPUART_HAL_EnableInterruptOnRxFull(LPUART1, true);
    LPUART_HAL_EnableInterruptOnRxFull(LPUART0, true);

    while (1)
    {
        __WFI();
    }
}

void LPUART0_Configuration(void)
{
    LPUART_HAL_Reset(LPUART0);
    LPUART_HAL_SetBaudrate(LPUART0, BSP_CLK_SPLLDIV2_HZ, APP_LPUART0_BAUDRATE);
    LPUART_HAL_EnableTx(LPUART0, true);
    LPUART_HAL_EnableRx(LPUART0, true);
}

void LPUART1_Configuration(void)
{
    LPUART_HAL_Reset(LPUART1);
    LPUART_HAL_SetBaudrate(LPUART1, BSP_CLK_SPLLDIV2_HZ, APP_LPUART1_BAUDRATE);
    LPUART_HAL_EnableTx(LPUART1, true);
    LPUART_HAL_EnableRx(LPUART1, true);
}

/*
* 1. 由LPUART1的接收过程触发
* 2. 从gLpuart1RxRBufStruct队列中取数
* 3. 填充LPUART0的发送缓存
*/
void LPUART0_TX_IRQHandler(void)
{
    uint8_t txDat;

    if ( LPUART_HAL_FLAG_TX_EMPTY_MASK == (LPUART_HAL_FLAG_TX_EMPTY_MASK & LPUART_HAL_GetStatus(LPUART0)) )
    {
        if ( RBUF_IsEmpty(&gLpuart1RxRBufStruct) ) /* 若是没有数据可转发，则关闭自己的发送过程 */
        {
            LPUART_HAL_EnableInterruptOnTxEmpty(LPUART0, false);
        }
        else
        {
            /* 从LUPART1的接收队列中取数，通过LPUART0转发 */
            txDat = RBUF_GetDataOut(&gLpuart1RxRBufStruct);
            LPUART_HAL_SetTxData(LPUART0, txDat);
            gLpuart0TxCounter++;
        }
    }
}

/*
* 1. 捕获LPUART0接收的数据
* 2. 向gLpuart0RxRBufStruct队列中转存数据
* 3. 触发LPUART1的发送过程
*/
void LPUART0_RX_IRQHandler(void)
{
    uint8_t rxDat;

    if ( LPUART_HAL_FLAG_RX_FULL_MASK == (LPUART_HAL_FLAG_RX_FULL_MASK & LPUART_HAL_GetStatus(LPUART0)) )
    {
        rxDat = LPUART_HAL_GetRxData(LPUART0);
        if (!RBUF_IsFull(&gLpuart0RxRBufStruct))
        {
            RBUF_PutDataIn(&gLpuart0RxRBufStruct, rxDat);
            /* 触发LPUART1的转发过程 */
            if (!LPUART_HAL_GetTxInterruptEnabled(LPUART1))
            {
                LPUART_HAL_EnableInterruptOnTxEmpty(LPUART1, true);
            }
        }
        else
        {
            gLpuart0OverflowCount++; /* 丢失数据计数 */
        }
    }
}

/*
* 1. 由LPUART0的接收过程触发
* 2. 从gLpuart0RxRBufStruct队列中取数
* 3. 填充LPUART1的发送缓存
*/
void LPUART1_TX_IRQHandler(void)
{
    uint8_t txDat;

    if ( LPUART_HAL_FLAG_TX_EMPTY_MASK == (LPUART_HAL_FLAG_TX_EMPTY_MASK & LPUART_HAL_GetStatus(LPUART1)) )
    {
        if ( RBUF_IsEmpty(&gLpuart0RxRBufStruct) ) /* 若是没有数据可转发，则关闭自己的发送过程 */
        {
            LPUART_HAL_EnableInterruptOnTxEmpty(LPUART1, false);
        }
        else
        {
            /* 从LUPART0的接收队列中取数，通过LPUART1转发 */
            txDat = RBUF_GetDataOut(&gLpuart0RxRBufStruct);
            LPUART_HAL_SetTxData(LPUART1, txDat);
            gLpuart1TxCounter++;
        }
    }
}

/*
* 1. 捕获LPUART1接收的数据
* 2. 向gLpuart1RxRBufStruct队列中转存数据
* 3. 触发LPUART0的发送过程
*/
void LPUART1_RX_IRQHandler(void)
{
    uint8_t rxDat;

    if ( LPUART_HAL_FLAG_RX_FULL_MASK == (LPUART_HAL_FLAG_RX_FULL_MASK & LPUART_HAL_GetStatus(LPUART1)) )
    {
        rxDat = LPUART_HAL_GetRxData(LPUART1);
        if (!RBUF_IsFull(&gLpuart1RxRBufStruct))
        {
            RBUF_PutDataIn(&gLpuart1RxRBufStruct, rxDat);

            /* 触发LPUART0的转发过程 */
            if (!LPUART_HAL_GetTxInterruptEnabled(LPUART0))
            {
                LPUART_HAL_EnableInterruptOnTxEmpty(LPUART0, true);
            }
        }
        else
        {
            gLpuart1OverflowCount++; /* 丢失数据计数 */
        }
    }
}

/* 配置蓝牙模块的控制引脚为断开连接并唤醒模式，从而保证可以进入AT命令访问状态
*/
void GPIO_Configuration(void)
{
    /* 配置WAKEUP为低电平，保持唤醒状态 */
    GPIO_SetPinLogic(BSP_GPIO_BLE_WAKEUP_PORT, BSP_GPIO_BLE_WAKEUP_PIN, eGPIO_LogicLevel_Low);
    GPIO_SetPinDir(BSP_GPIO_BLE_WAKEUP_PORT, BSP_GPIO_BLE_WAKEUP_PIN, eGPIO_Direction_Output);

    /* 配置DISCON为低电平，保持断开状态 */
    GPIO_SetPinLogic(BSP_GPIO_BLE_DISCON_PORT, BSP_GPIO_BLE_DISCON_PIN, eGPIO_LogicLevel_Low);
    GPIO_SetPinDir(BSP_GPIO_BLE_DISCON_PORT, BSP_GPIO_BLE_DISCON_PIN, eGPIO_Direction_Output);
}

/******************************************************************************
 * NVIC.
 *****************************************************************************/
/*
* 配置NVIC中断管理单元
* 1. 在NVIC中解锁必要的中断向量
* 2. 设定各中断向量的优先级
* 3. 在KE18F中实现了4个有效的优先级位，具体查看 __NVIC_PRIO_BITS.
* 4. 优先级的值越小，级别越高
*/
#define __NVIC_PRIO(preep, sub) ((((preep) & 0x3) << 2) | (sub & 0x3) )
void NVIC_Configuration(void)
{
    NVIC_SetPriorityGrouping(5U); /* 最高2位为可抢占优先级，低2位为不可抢占优先级 */
    NVIC_SetPriority(LPUART1_RX_IRQn,  __NVIC_PRIO(1, 1));
    NVIC_SetPriority(LPUART0_RX_IRQn,  __NVIC_PRIO(2, 1));
    NVIC_SetPriority(LPUART0_TX_IRQn,  __NVIC_PRIO(3, 1));
    NVIC_SetPriority(LPUART1_TX_IRQn,  __NVIC_PRIO(3, 1));

    NVIC_EnableIRQ(LPUART1_RX_IRQn);
    NVIC_EnableIRQ(LPUART0_RX_IRQn);
    NVIC_EnableIRQ(LPUART0_TX_IRQn);
    NVIC_EnableIRQ(LPUART1_TX_IRQn);
}

/* EOF. */

